home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Frameworks / Hsoi's App Shell 1.0a4 / HAS Other Source / WASTE 1.3a4 Distribution / WASTE 1.3a4 / Source / WEBirthDeath.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-04  |  20.4 KB  |  835 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    WEBirthDeath.c
  3.  *
  4.  *    WASTE PROJECT
  5.  *  Creation and Destruction, Standard Procs, etc.
  6.  *
  7.  *  Copyright (c) 1993-1997 Marco Piovanelli
  8.  *    All Rights Reserved
  9.  *
  10.  *  C port by Dan Crevier
  11.  *
  12.  */
  13.  
  14.  
  15. #include "WASTEIntf.h"
  16.  
  17. #if GENERATINGCFM
  18. #ifndef __CODEFRAGMENTS__
  19. #include <CodeFragments.h>
  20. #endif
  21. #endif
  22.  
  23. const Point kOneToOneScaling = { 1, 1 };
  24.  
  25. // static variables
  26.  
  27. static WEDrawTextUPP        _weStdDrawTextProc = nil;
  28. static WEPixelToCharUPP        _weStdPixelToCharProc = nil;
  29. static WECharToPixelUPP        _weStdCharToPixelProc = nil;
  30. static WELineBreakUPP        _weStdLineBreakProc = nil;
  31. static WEWordBreakUPP        _weStdWordBreakProc = nil;
  32. static WECharByteUPP        _weStdCharByteProc = nil;
  33. static WECharTypeUPP        _weStdCharTypeProc = nil;
  34. static WEClickLoopUPP        _weStdClickLoopProc = nil;
  35. static WEHiliteDropAreaUPP    _weStdHiliteDropAreaProc = nil;
  36. static WEEraseUPP            _weStdEraseProc = nil;
  37.  
  38. static pascal void _WEStdDrawText(Ptr pText, SInt32 textLength, Fixed slop,
  39.                 JustStyleCode styleRunPosition, WEHandle hWE)
  40. {
  41. #pragma unused(hWE)
  42.     DrawJustified(pText, textLength, slop, styleRunPosition,
  43.           kOneToOneScaling, kOneToOneScaling);
  44. }
  45.  
  46. static pascal SInt32 _WEStdPixelToChar(Ptr pText, SInt32 textLength, Fixed slop,
  47.                 Fixed *width, WEEdge *edge, JustStyleCode styleRunPosition,
  48.                 Fixed hPos, WEHandle hWE)
  49. {
  50. #pragma unused(hPos, hWE)
  51.     Fixed lastWidth;
  52.     SInt32 offset;
  53.  
  54.     lastWidth = *width;
  55.     offset = PixelToChar(pText, textLength, slop, lastWidth, (Boolean *) edge,
  56.         width, styleRunPosition, kOneToOneScaling, kOneToOneScaling);
  57.  
  58.     // round width to nearest integer value
  59.     // (this is supposed to fix an incompatibility with the WorldScript Power Adapter)
  60.     *width = (*width + 0x00008000) & 0xFFFF0000;
  61.  
  62.     return offset;
  63. }
  64.  
  65. static pascal SInt16 _WEStdCharToPixel(Ptr pText, SInt32 textLength, Fixed slop,
  66.                 SInt32 offset, SInt16 direction, JustStyleCode styleRunPosition,
  67.                 SInt16 hPos, WEHandle hWE)
  68. {
  69. #pragma unused(hPos, hWE)
  70.     return CharToPixel(pText, textLength, slop, offset, direction,
  71.             styleRunPosition, kOneToOneScaling, kOneToOneScaling);
  72. }
  73.  
  74. static pascal StyledLineBreakCode _WEStdLineBreak(Ptr pText, SInt32 textLength,
  75.                 SInt32 textStart, SInt32 textEnd, Fixed *textWidth,
  76.                 SInt32 *textOffset, WEHandle hWE)
  77. {
  78. #pragma unused(hWE)
  79.     return StyledLineBreak(pText, textLength, textStart, textEnd, 0, textWidth,
  80.                 textOffset);
  81. }
  82.  
  83. static pascal void _WEStdWordBreak(Ptr pText, SInt16 textLength, SInt16 offset,
  84.                 WEEdge edge, OffsetTable breakOffsets, ScriptCode script,
  85.                 WEHandle hWE)
  86. {
  87. #pragma unused(hWE)
  88.     FindWordBreaks(pText, textLength, offset, (Boolean) edge, nil, breakOffsets, script);
  89. }
  90.  
  91. static pascal SInt16 _WEStdCharByte(Ptr pText, SInt16 textOffset, ScriptCode script,
  92.                 WEHandle hWE)
  93. {
  94. #pragma unused(hWE)
  95.     return CharacterByteType(pText, textOffset, script);
  96. }
  97.  
  98. static pascal SInt16 _WEStdCharType(Ptr pText, SInt16 textOffset, ScriptCode script,
  99.                 WEHandle hWE)
  100. {
  101. #pragma unused(hWE)
  102.     return CharacterType(pText, textOffset, script);
  103. }
  104.  
  105. //    _WEScriptToFont, _WEOldWordBreak, _WEOldCharByte and _WEOldCharType
  106. //    are only needed to support version 7.0 / 7.0.1 of MacOS;
  107. //    CFM-based code (both PowerPC and CFM68K) doesn't need these routines
  108. //    as the Code Fragment Manager requires at least MacOS 7.1.2
  109. //    (on the PowerPC) or MacOS 7.1 (for CFM68K)
  110.  
  111. #if ! (SystemSevenFiveOrLater || GENERATINGCFM)
  112.  
  113. pascal SInt16 _WEScriptToFont(ScriptCode script)
  114. {
  115.     // given an explicit script code, return the first font ID in the corresponding range
  116.     // for an explanation of the formula given below, see IM: Text, page B-8
  117.  
  118.     if (script == smRoman)
  119.     {
  120.         return 2;
  121.     }
  122.     else if ((script > smRoman) && (script <= smUninterp))
  123.     {
  124.         return (0x3E00 + 0x200 * script);
  125.     }
  126.     else
  127.     {
  128.         return systemFont;    // unknown script code (?)
  129.     }
  130. }
  131.  
  132. static pascal void _WEOldWordBreak(Ptr pText, SInt16 textLength, SInt16 offset,
  133.                 WEEdge edge, OffsetTable breakOffsets, ScriptCode script,
  134.                 WEHandle hWE)
  135. {
  136.     GrafPtr savePort, tempPort;
  137.     SInt16 saveFont;
  138.  
  139.     // the old (now obsolete) FindWord routine gets an implicit script parameter through
  140.     // the current graphics port txFont field, so first of all we must have a valid port
  141.     GetPort(&savePort);
  142.     tempPort = (*hWE)->port;
  143.     SetPort(tempPort);
  144.  
  145.     // then set the txFont field to a font number in the specified script range
  146.     saveFont = tempPort->txFont;
  147.     TextFont(_WEScriptToFont(script));
  148.  
  149.     // call _FindWord
  150.     FindWord(pText, textLength, offset, (Boolean)edge, nil, breakOffsets);
  151.  
  152.     // restore font and port
  153.     TextFont(saveFont);
  154.     SetPort(savePort);
  155.  
  156. }
  157.  
  158. static pascal SInt16 _WEOldCharByte(Ptr pText, SInt16 textOffset, ScriptCode script,
  159.                 WEHandle hWE)
  160. {
  161.     GrafPtr savePort, tempPort;
  162.     SInt16 saveFont;
  163.     SInt16 retVal;
  164.  
  165.     // the old (now obsolete) CharByte routine gets an implicit script parameter through
  166.     // the current graphics port txFont field, so first of all we must have a valid port
  167.     GetPort(&savePort);
  168.     tempPort = (*hWE)->port;
  169.     SetPort(tempPort);
  170.  
  171.     // then set the txFont field to a font number in the specified script range
  172.     saveFont = tempPort->txFont;
  173.     TextFont(_WEScriptToFont(script));
  174.  
  175.     // call _CharByte
  176.     retVal = CharByte(pText, textOffset);
  177.  
  178.     // restore font and port
  179.     TextFont(saveFont);
  180.     SetPort(savePort);
  181.  
  182.     return retVal;
  183. }
  184.  
  185. static pascal SInt16 _WEOldCharType(Ptr pText, SInt16 textOffset, ScriptCode script,
  186.                 WEHandle hWE)
  187. {
  188.     GrafPtr savePort, tempPort;
  189.     SInt16 saveFont;
  190.     SInt16 retVal;
  191.  
  192.     // the old (now obsolete) CharType routine gets an implicit script parameter through
  193.     // the current graphics port txFont field, so first of all we must have a valid port
  194.     GetPort(&savePort);
  195.     tempPort = (*hWE)->port;
  196.     SetPort(tempPort);
  197.  
  198.     // then set the txFont field to a font number in the specified script range
  199.     saveFont = tempPort->txFont;
  200.     TextFont(_WEScriptToFont(script));
  201.  
  202.     // call _CharType
  203.     retVal = CharType(pText, textOffset);
  204.  
  205.     // restore font and port
  206.     TextFont(saveFont);
  207.     SetPort(savePort);
  208.  
  209.     return retVal;
  210.  
  211. }
  212.  
  213. #endif
  214.  
  215. static pascal Boolean _WEStdClickLoop(WEHandle hWE)
  216. {
  217.     WEPtr pWE = *hWE;        // assume WE record is already locked
  218.     Point mouseLoc;
  219.     SInt32 currentOffset;
  220.     SInt32 maxOffset;
  221.     SInt32 vDelta = 0;
  222.     SInt32 hDelta = 0;
  223.  
  224.     // do nothing if auto-scroll is disabled or if we're inactive
  225.     if (!BTST(pWE->features, weFAutoScroll) || !BTST(pWE->flags, weFActive))
  226.     {
  227.         return true;
  228.     }
  229.  
  230.     // get current mouse location, in local coords
  231.     // we can safely assume the graphics port is set up correctly
  232.     GetMouse(&mouseLoc);
  233.  
  234.     // HANDLE VERTICAL AUTOSCROLL
  235.     currentOffset = pWE->viewRect.top - pWE->destRect.top;
  236.     maxOffset = (pWE->destRect.bottom - pWE->destRect.top) - (pWE->viewRect.bottom - pWE->viewRect.top);
  237.  
  238.     // is the mouse below the view rect?
  239.     if (mouseLoc.v > pWE->viewRect.bottom)
  240.     {
  241.         // is there anything hidden below the view rect?
  242.         if (currentOffset < maxOffset)
  243.         {
  244.             // then scroll down: calculate the scroll delta
  245.             vDelta = pWE->viewRect.bottom - mouseLoc.v;
  246.  
  247.             // pin the new vertical offset to the bottom of the dest rectangle
  248.             if (vDelta < (currentOffset - maxOffset))
  249.             {
  250.                 vDelta = currentOffset - maxOffset;
  251.             }
  252.  
  253.             // never scroll by more than kMaxScrollDelta pixels
  254.             if (vDelta < -kMaxScrollDelta)
  255.             {
  256.                 vDelta = -kMaxScrollDelta;
  257.             }
  258.         }
  259.     }
  260.  
  261.     // is the mouse above the view rect?
  262.     else if (mouseLoc.v < pWE->viewRect.top)
  263.     {
  264.         // is there anything hidden above the view rect?
  265.         if (currentOffset > 0)
  266.         {
  267.             // then scroll up: calculate the scroll delta
  268.             vDelta = pWE->viewRect.top - mouseLoc.v;
  269.  
  270.             // pin the new vertical offset to the top of the dest rectangle
  271.             if (vDelta > currentOffset)
  272.             {
  273.                 vDelta = currentOffset;
  274.             }
  275.  
  276.             // never scroll by more than kMaxScrollDelta pixels
  277.             if (vDelta > kMaxScrollDelta)
  278.             {
  279.                 vDelta = kMaxScrollDelta;
  280.             }
  281.         }
  282.     }
  283.  
  284.     // HANDLE HORIZONTAL AUTOSCROLL
  285.     currentOffset = pWE->viewRect.left - pWE->destRect.left;
  286.     maxOffset = (pWE->destRect.right - pWE->destRect.left) - (pWE->viewRect.right - pWE->viewRect.left);
  287.  
  288.     // is the mouse to the right of the view rect?
  289.     if (mouseLoc.h > pWE->viewRect.right)
  290.     {
  291.         // is there anything hidden to the right of the view rect?
  292.         if (currentOffset < maxOffset)
  293.         {
  294.             // then scroll right: calculate the scroll delta
  295.             hDelta = pWE->viewRect.right - mouseLoc.h;
  296.  
  297.             // pin the new vertical offset to the rightmost edge
  298.             // of the dest rectangle
  299.             if (hDelta < (currentOffset - maxOffset))
  300.             {
  301.                 hDelta = currentOffset - maxOffset;
  302.             }
  303.  
  304.             // never scroll by more than kMaxScrollDelta pixels
  305.             if (hDelta < -kMaxScrollDelta)
  306.             {
  307.                 hDelta = -kMaxScrollDelta;
  308.             }
  309.         }
  310.     }
  311.  
  312.     // is the mouse to the left of the view rect?
  313.     else if (mouseLoc.h < pWE->viewRect.left)
  314.     {
  315.         // is there anything hidden to the left of the view rect?
  316.         if (currentOffset > 0)
  317.         {
  318.             // then scroll up: calculate the scroll delta
  319.             hDelta = pWE->viewRect.left - mouseLoc.h;
  320.  
  321.             // pin the new horizontal offset to the leftmost edge
  322.             // of the dest rectangle
  323.             if (hDelta > currentOffset)
  324.             {
  325.                 hDelta = currentOffset;
  326.             }
  327.  
  328.             // never scroll by more than kMaxScrollDelta pixels
  329.             if (hDelta > kMaxScrollDelta)
  330.             {
  331.                 hDelta = kMaxScrollDelta;
  332.             }
  333.         }
  334.     }
  335.  
  336.     if ((vDelta != 0) || (hDelta != 0))
  337.     {
  338.         // do the scroll
  339.         WEScroll(hDelta, vDelta, hWE);
  340.  
  341.         // notify our client we have scrolled the text
  342.         if (pWE->scrollProc != nil)
  343.         {
  344.             CallWEScrollProc(hWE, pWE->scrollProc);
  345.         }
  346.     }
  347.  
  348.     return true;
  349. }
  350.  
  351. static pascal OSErr _WEStdHiliteDropArea(DragReference drag, Boolean hiliteFlag, WEHandle hWE)
  352. {
  353.     WEPtr pWE = *hWE;        // assume WE record is already locked
  354.     RgnHandle tmpRgn;
  355.     OSErr err;
  356.  
  357.     if (hiliteFlag)
  358.     {
  359.         tmpRgn = NewRgn();
  360.         CopyRgn(pWE->viewRgn, tmpRgn);
  361.         InsetRgn(tmpRgn, -kTextMargin, -kTextMargin);
  362.         err = ShowDragHilite(drag, tmpRgn, true);
  363.         DisposeRgn(tmpRgn);
  364.     }
  365.     else
  366.     {
  367.         err = HideDragHilite(drag);
  368.     }
  369.     return err;
  370. }
  371.  
  372. static pascal void _WEStdErase(const Rect *area, WEHandle hWE)
  373. {
  374. #pragma unused(hWE)
  375.     EraseRect(area);
  376. }
  377.  
  378. pascal OSErr _WERegisterWithTSM(WEHandle hWE)
  379. {
  380.     WEPtr pWE = *hWE;    // assume WE record is already locked
  381.     InterfaceTypeList typeList;
  382.     OSErr err;
  383.  
  384.     // do nothing if the Text Services Manager isn't available
  385.     if (BTST(pWE->flags, weFHasTextServices))
  386.     {
  387.         typeList[0] = kTextService;
  388.         if ((err = NewTSMDocument(1, typeList, &pWE->tsmReference, (SInt32) hWE)) != noErr)
  389.         {
  390.             // we don't consider it an error if our client application isn't TSM-aware
  391.             if (err != tsmNeverRegisteredErr)
  392.             {
  393.                 goto cleanup;
  394.             }
  395.         }
  396.     }
  397.  
  398.     // clear result code
  399.     err = noErr;
  400.  
  401. cleanup:
  402.     // return result code
  403.     return err;
  404. }
  405.  
  406. pascal void _WESetStandardHooks(WEHandle hWE)
  407. {
  408.     WEPtr pWE;
  409.  
  410.     // the first time we're called, create routine descriptors
  411.     if (_weStdDrawTextProc == nil)
  412.     {
  413.         _weStdDrawTextProc = NewWEDrawTextProc(_WEStdDrawText);
  414.         _weStdPixelToCharProc = NewWEPixelToCharProc(_WEStdPixelToChar);
  415.         _weStdCharToPixelProc = NewWECharToPixelProc(_WEStdCharToPixel);
  416.         _weStdLineBreakProc = NewWELineBreakProc(_WEStdLineBreak);
  417.  
  418. #if ! (SystemSevenFiveOrLater || GENERATINGCFM)
  419.  
  420.         if (GetScriptManagerVariable(smVersion) < 0x0710)
  421.         {
  422.             // pre-7.1 version of the Script Manager: must use old hooks
  423.             _weStdWordBreakProc = NewWEWordBreakProc(_WEOldWordBreak);
  424.             _weStdCharByteProc = NewWECharByteProc(_WEOldCharByte);
  425.             _weStdCharTypeProc = NewWECharTypeProc(_WEOldCharType);
  426.         }
  427.         else
  428. #endif
  429.         {
  430.             // Script Manager version 7.1 or newer
  431.             _weStdWordBreakProc = NewWEWordBreakProc(_WEStdWordBreak);
  432.             _weStdCharByteProc = NewWECharByteProc(_WEStdCharByte);
  433.             _weStdCharTypeProc = NewWECharTypeProc(_WEStdCharType);
  434.         }
  435.  
  436.         _weStdClickLoopProc = NewWEClickLoopProc(_WEStdClickLoop);
  437.         _weStdHiliteDropAreaProc = NewWEHiliteDropAreaProc(_WEStdHiliteDropArea);
  438.         _weStdEraseProc = NewWEEraseProc(_WEStdErase);
  439.  
  440.     } // if called for the first time
  441.  
  442.     // replace null hook fields with the addresses of the standard hooks
  443.  
  444.     pWE = *hWE;
  445.  
  446.     if (pWE->drawTextHook == nil)
  447.     {
  448.         pWE->drawTextHook = _weStdDrawTextProc;
  449.     }
  450.     if (pWE->pixelToCharHook == nil)
  451.     {
  452.         pWE->pixelToCharHook = _weStdPixelToCharProc;
  453.     }
  454.     if (pWE->charToPixelHook == nil)
  455.     {
  456.         pWE->charToPixelHook = _weStdCharToPixelProc;
  457.     }
  458.     if (pWE->lineBreakHook == nil)
  459.     {
  460.         pWE->lineBreakHook = _weStdLineBreakProc;
  461.     }
  462.     if (pWE->wordBreakHook == nil)
  463.     {
  464.         pWE->wordBreakHook = _weStdWordBreakProc;
  465.     }
  466.     if (pWE->charByteHook == nil)
  467.     {
  468.         pWE->charByteHook = _weStdCharByteProc;
  469.     }
  470.     if (pWE->charTypeHook == nil)
  471.     {
  472.         pWE->charTypeHook = _weStdCharTypeProc;
  473.     }
  474.     if (pWE->clickLoop == nil)
  475.     {
  476.         pWE->clickLoop = _weStdClickLoopProc;
  477.     }
  478.     if (pWE->hiliteDropAreaHook == nil)
  479.     {
  480.         pWE->hiliteDropAreaHook = _weStdHiliteDropAreaProc;
  481.     }
  482.     if (pWE->eraseHook == nil)
  483.     {
  484.         pWE->eraseHook = _weStdEraseProc;
  485.     }
  486. }
  487.  
  488. pascal OSErr WENew(const LongRect *destRect, const LongRect *viewRect, UInt32 features, WEHandle *hWE)
  489. {
  490.     WEPtr pWE = nil;
  491.     UInt32 allocFlags = kAllocClear;
  492.     SInt32 response;
  493.     Rect r;
  494.     WERunAttributes attributes;
  495.     OSErr err;
  496.  
  497.     // allocate the WE record
  498.     if ((err = _WEAllocate(sizeof(WERec), allocFlags, (Handle *)hWE)) != noErr)
  499.     {
  500.         goto cleanup;
  501.     }
  502.  
  503.     // lock it down
  504.     HLock((Handle)*hWE);
  505.     pWE = **hWE;
  506.  
  507.     // get active port
  508.     GetPort(&pWE->port);
  509.  
  510.     // determine whether temporary memory should be used for data structures
  511.     if (BTST(features, weFUseTempMem))
  512.     {
  513.         allocFlags += kAllocTemp;
  514.     }
  515.  
  516.     // allocate the text handle (initially empty)
  517.     if ((err = _WEAllocate(0, allocFlags, (Handle *)&pWE->hText)) != noErr)
  518.     {
  519.         goto cleanup;
  520.     }
  521.  
  522.     // allocate the line array
  523.     if ((err = _WEAllocate(2 * sizeof(WELineRec), allocFlags, (Handle *)&pWE->hLines)) != noErr)
  524.     {
  525.         goto cleanup;
  526.     }
  527.  
  528.     // allocate the style table
  529.     if ((err = _WEAllocate(sizeof(WEStyleTableEntry), allocFlags, (Handle *)&pWE->hStyles)) != noErr)
  530.     {
  531.         goto cleanup;
  532.     }
  533.  
  534.     // allocate the run array
  535.     if ((err = _WEAllocate(2 * sizeof(WERunArrayEntry), allocFlags, (Handle *)&pWE->hRuns)) != noErr)
  536.     {
  537.         goto cleanup;
  538.     }
  539.  
  540.     // allocate the user info array
  541.     if ((err = _WEAllocate(sizeof(WEUserInfoEntry), allocFlags, &pWE->hUserInfo)) != noErr)
  542.     {
  543.         goto cleanup;
  544.     }
  545.  
  546.     // check for the presence of various system software features
  547.     // determine whether Color Quickdraw is available
  548.     if ((Gestalt(gestaltQuickdrawVersion, &response) == noErr) && (response >= gestalt8BitQD))
  549.     {
  550.         BSET(pWE->flags, weFHasColorQD);
  551.     }
  552.  
  553.     // determine whether the Drag Manager is available
  554.     if ((Gestalt(gestaltDragMgrAttr, &response) == noErr) && BTST(response, gestaltDragMgrPresent))
  555.     {
  556. #if GENERATINGCFM
  557.         if ((UInt32) NewDrag != kUnresolvedCFragSymbolAddress)
  558. #endif
  559.             BSET(pWE->flags, weFHasDragManager);
  560.  
  561. #if WASTE_TRANSLUCENT_DRAGS
  562.         // determine whether translucent drags are available
  563.         if (BTST(response, 3))
  564.         {
  565. #if GENERATINGCFM
  566.             if ((UInt32) SetDragImage != kUnresolvedCFragSymbolAddress)
  567. #endif
  568.                 BSET(pWE->flags, weFHasTranslucentDrags);
  569.         }
  570. #endif
  571.     }
  572.  
  573.     // determine whether the Text Services manager is available
  574.     if (Gestalt(gestaltTSMgrVersion, &response) == noErr)
  575.     {
  576.         BSET(pWE->flags, weFHasTextServices);
  577.     }
  578.  
  579.     // determine if there are any non-Roman scripts enabled
  580.     if (GetScriptManagerVariable(smEnabled) > 1)
  581.     {
  582.         BSET(pWE->flags, weFNonRoman);
  583.  
  584.         // determine whether a double-byte script is installed
  585.         if (GetScriptManagerVariable(smDoubleByte) != 0)
  586.         {
  587. #if GENERATING68K
  588.             BSET(pWE->flags, weFDoubleByte);    // the WorldScript Power Adapter breaks this :-(
  589. #else
  590.             ScriptCode script;
  591.             for ( script = smRoman; script <= smKlingon; script++ )
  592.             {
  593.                 if (GetScriptVariable(script, smEnabled) &&
  594.                 ! BTST(GetScriptVariable(script, smScriptFlags), smsfSingByte))
  595.                 {
  596.                     BSET(pWE->flags, weFDoubleByte);
  597.                     break;
  598.                 }
  599.             }
  600. #endif
  601.         }
  602.  
  603.         // determine whether a bidirectional script is installed
  604.         if (GetScriptManagerVariable(smBidirect) != 0)
  605.         {
  606.             BSET(pWE->flags, weFBidirectional);
  607.         }
  608.     }
  609.  
  610.     // initialize miscellaneous fields of the WE record
  611.     pWE->nLines = 1;
  612.     pWE->nStyles = 1;
  613.     pWE->nRuns = 1;
  614.     pWE->viewRect = *viewRect;
  615.     pWE->destRect = *destRect;
  616.     pWE->direction = weDirDefault;
  617.     pWE->features = features;
  618.     pWE->tsmAreaStart = kInvalidOffset;
  619.     pWE->tsmAreaEnd = kInvalidOffset;
  620.     pWE->dragCaretOffset = kInvalidOffset;
  621.  
  622.     // initialize hook fields with the addresses of the standard hooks
  623.     _WESetStandardHooks(*hWE);
  624.  
  625.     // create a region to hold the view rectangle
  626.     pWE->viewRgn = NewRgn();
  627.     WELongRectToRect(viewRect, &r);
  628.     RectRgn(pWE->viewRgn, &r);
  629.  
  630.     // initialize the style run array
  631.     (*pWE->hRuns)[1].runStart = 1;
  632.     (*pWE->hRuns)[1].styleIndex = -1;
  633.  
  634.     // initialize the style table
  635.     (*pWE->hStyles)[0].refCount = 1;
  636.  
  637.     // copy text attributes from the active graphics port
  638.     BLOCK_CLR(attributes);
  639.     attributes.runStyle.tsFont = pWE->port->txFont;
  640.     attributes.runStyle.tsSize = pWE->port->txSize;
  641.     attributes.runStyle.tsFace = pWE->port->txFace;
  642.     if (BTST(pWE->flags, weFHasColorQD))
  643.     {
  644.         GetForeColor(&attributes.runStyle.tsColor);
  645.     }
  646.     _WEFillFontInfo(pWE->port, &attributes);
  647.     (*pWE->hStyles)[0].info = attributes;
  648.  
  649.     // initialize the line array
  650.     if ((err = WECalText(*hWE)) != noErr)
  651.     {
  652.         goto cleanup;
  653.     }
  654.  
  655.     // register with the Text Services Manager
  656.     if ((err = _WERegisterWithTSM(*hWE)) != noErr)
  657.     {
  658.         goto cleanup;
  659.     }
  660.  
  661.     // unlock the WE record
  662.     HUnlock((Handle)*hWE);
  663.  
  664.     // skip clean-up section
  665.     return noErr;
  666.  
  667. cleanup:
  668.     // clean up
  669.     if (pWE != nil)
  670.     {
  671.         _WEForgetHandle((Handle *) &pWE->hText);
  672.         _WEForgetHandle((Handle *) &pWE->hLines);
  673.         _WEForgetHandle((Handle *) &pWE->hStyles);
  674.         _WEForgetHandle((Handle *) &pWE->hRuns);
  675.         _WEForgetHandle(&pWE->hUserInfo);
  676.         if (pWE->viewRgn != nil)
  677.         {
  678.             DisposeRgn(pWE->viewRgn);
  679.         }
  680.     }
  681.     _WEForgetHandle((Handle *)hWE);
  682.  
  683.     return err;
  684. }
  685.  
  686. pascal void _WEResetStyleTable(WEHandle hWE)
  687. {
  688.     WEPtr pWE = *hWE;    // assume WE record is already locked
  689.     SInt32 index;
  690.     WEStyleTableEntry *pTable;
  691.     Boolean saveTableLock;
  692.  
  693.     // sanity check
  694.     if (pWE->hStyles == nil)
  695.     {
  696.         return;
  697.     }
  698.  
  699.     // lock the style table
  700.     saveTableLock = _WESetHandleLock((Handle) pWE->hStyles, true);
  701.     pTable = *pWE->hStyles;
  702.  
  703.     // walk the style table, disposing of all embedded objects referenced there
  704.     index = pWE->nStyles;
  705.     while ( --index >= 0 )
  706.     {
  707.  
  708. #if WASTE_OBJECTS
  709.         if ((pTable->refCount > 0) && (pTable->info.runStyle.tsObject != nil))
  710.         {
  711.             _WEFreeObject(pTable->info.runStyle.tsObject);
  712.         }
  713. #endif
  714.  
  715.         pTable->refCount = 0;
  716.         pTable++;
  717.     };
  718.  
  719.     // unlock the style table
  720.     _WESetHandleLock((Handle) pWE->hStyles, saveTableLock);
  721. }
  722.  
  723. pascal void WEDispose(WEHandle hWE)
  724. {
  725.     WEPtr pWE;
  726.  
  727.     // sanity check: make sure WE isn't nil
  728.     if (hWE == nil)
  729.     {
  730.         return;
  731.     }
  732.  
  733.     // lock the WE record
  734.     HLock((Handle) hWE);
  735.     pWE = *hWE;
  736.  
  737.     // clear the Undo buffer
  738.     _WEForgetAction(&pWE->hActionStack);
  739.  
  740.     // unregister with the Text Services Manager
  741.     if (pWE->tsmReference != nil)
  742.     {
  743.         DeleteTSMDocument(pWE->tsmReference);
  744.         pWE->tsmReference = nil;
  745.     }
  746.  
  747.     // dispose of the offscreen graphics world
  748.     if (pWE->offscreenPort != nil)
  749.     {
  750.         DisposeGWorld((GWorldPtr)pWE->offscreenPort);
  751.         pWE->offscreenPort = nil;
  752.     }
  753.  
  754. #if WASTE_OBJECTS
  755.     // release all embedded objects we know about
  756.     _WEResetStyleTable(hWE);
  757.  
  758.     // dispose instance-specific object handler table
  759.     _WEForgetHandle((Handle *) &pWE->hObjectHandlerTable);
  760. #endif
  761.  
  762.     // dispose of auxiliary data structures
  763.     _WEForgetHandle((Handle *) &pWE->hText);
  764.     _WEForgetHandle((Handle *) &pWE->hLines);
  765.     _WEForgetHandle((Handle *) &pWE->hStyles);
  766.     _WEForgetHandle((Handle *) &pWE->hRuns);
  767.     _WEForgetHandle(&pWE->hUserInfo);
  768.     DisposeRgn(pWE->viewRgn);
  769.  
  770.     // dispose of the WE record
  771.     DisposeHandle((Handle) hWE);
  772. }
  773.  
  774. pascal OSErr WEUseText(Handle text, WEHandle hWE)
  775. {
  776.     WEPtr pWE;
  777.     WERunArrayEntry *pRuns;
  778.     WELineRec *pLines;
  779.     SInt32 textLength;
  780.     Boolean saveWELock;
  781.  
  782.     // lock the WE record
  783.     saveWELock = _WESetHandleLock((Handle) hWE, true);
  784.     pWE = *hWE;
  785.  
  786.     // stop any ongoing inline session
  787.     WEStopInlineSession(hWE);
  788.  
  789.     // reset modification count and clear undo buffer, if any
  790.     WEResetModCount(hWE);
  791.  
  792.     // reset the style table, disposing of all embedded objects it references
  793.     _WEResetStyleTable(hWE);
  794.  
  795.     // install the text
  796.     _WEForgetHandle(&pWE->hText);
  797.     pWE->hText = text;
  798.     textLength = GetHandleSize(text);
  799.     pWE->textLength = textLength;
  800.  
  801.     // reset the run array
  802.     SetHandleSize((Handle) pWE->hRuns, 2 * sizeof(WERunArrayEntry));
  803.     pWE->nRuns = 1;
  804.     pRuns = *pWE->hRuns;
  805.     pRuns[1].runStart = textLength + 1;
  806.     pRuns[1].styleIndex = -1;
  807.  
  808.     // fix the refCount of the style table entry referenced by the only run
  809.     (*pWE->hStyles)[pRuns[0].styleIndex].refCount = 1;
  810.  
  811.     // reset the line array
  812.     SetHandleSize((Handle) pWE->hLines, 2 * sizeof(WELineRec));
  813.     pWE->nLines = 1;
  814.     pLines = *pWE->hLines;
  815.     _WEBlockClr(pLines, 2 * sizeof(WELineRec));
  816.     pLines[1].lineStart = textLength;
  817.  
  818.     // reset several fields of the WE record
  819.     pWE->selStart = 0;
  820.     pWE->selEnd = 0;
  821.     pWE->firstByte = 0;
  822.     pWE->clickCount = 0;
  823.     pWE->tsmAreaStart = kInvalidOffset;
  824.     pWE->tsmAreaEnd = kInvalidOffset;
  825.     pWE->dragCaretOffset = kInvalidOffset;
  826.  
  827.     // recalculate and redraw everything
  828.     // err = _WERedraw(0, LONG_MAX, hWE);
  829.  
  830.     // unlock the WE record
  831.     _WESetHandleLock((Handle) hWE, saveWELock);
  832.  
  833.     return noErr;
  834. }
  835.